package com.sbtr.common.calculate;
import org.junit.Assert;
import org.junit.Test;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author maojianping
 * @Date 2023/4/1 15:16
 * @Version 1.0
 * 用途：普通公式解析计算，属性生成模块算子使用
 * 前端算子模块支持输入函数有：
 *    1：2+3*5（常数字符串四则运算）
 *    2：(a + b) * c / 2 （字符串字母类型四则运算）
 *    3：Math.abs(x)：返回x的绝对值
 *    4：Math.ceil(x)：返回大于等于x的最小整数
 *    5：Math.floor(x)：返回小于等于x的最大整数
 *    6：Math.max(x1, x2, ..., xn)：返回x1, x2, ..., xn中的最大值
 *    7：Math.min(x1, x2, ..., xn)：返回x1, x2, ..., xn中的最小值
 *    8：Math.pow(x, y)：返回x的y次幂
 *    9：Math.random()：返回0到1之间的随机数
 *    10：Math.round(x)：返回x四舍五入后的整数
 *    11：Math.sqrt(x)：返回x的平方根
 */
public class CalculatorUtils {

    /**
     * Java Script Engine API进行替换计算
     * 引擎不支持中文，必须使用英文
     * @param formula
     * @param variables
     * @return
     * @throws Exception
     */
    public static double evaluate(String formula, Map<String, Double> variables) throws Exception {
        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine engine = mgr.getEngineByName("JavaScript"); // 调用JS引擎
        for (Map.Entry<String, Double> variable : variables.entrySet()) {
            engine.put(variable.getKey(), variable.getValue());
        }
//        String replacedFormula = formula.replaceAll("(?<=[^a-zA-Z])\\w+(?=[^a-zA-Z])", "$0");// 容易出现变量连接错误
        String replacedFormula = formula.replaceAll("(?<=[^a-zA-Z0-9._])\\w+(?=[^a-zA-Z0-9._])", "($0 + 0.0)");
//        String replacedFormula = formula.replaceAll("(?<=[^+\\-*/(])\\+", "+0.0+");
        try {
            Object result = engine.eval(replacedFormula);
            return Double.valueOf(result.toString());
        } catch (ScriptException e) {
            throw new RuntimeException("输入公式有误，请检查重新填写: " + formula, e);
        }
    }

    /**
     * 测试前端属性生成公式：测试evaluate方法是否能够正确计算简单的数学表达式
     */
    @Test
    public void testEvaluate() throws Exception {

        String formula1 = "2+3*4/2-1";
        Map<String, Double> variables1 = new HashMap<>();
        System.out.println("2+3*4/2-1: " + evaluate(formula1, variables1)); // 输出结果

        String formula2 = "x + z * 3"; // 输入要计算的表达式，测试多余参数输入
        Map<String, Double> variables2 = new HashMap<String, Double>(); // 输入变量值
        variables2.put("x", 1.0);
        variables2.put("z", 2.0);
        variables2.put("H", 12.0);
        System.out.println(formula2+": " + evaluate(formula2, variables2)); // 输出结果

       // 测试案例2
        Map<String, Double> variables3 = new HashMap<>();
        variables3.put("a", 1.0);
        variables3.put("b", 2.0);
        variables3.put("c", 3.0);
        System.out.println("(a + b) * c / 2: " + evaluate("(a + b) * c / 2", variables3)); // 输出结果

        Map<String, Double> variables4 = new HashMap<>();
        variables4.put("x_1", 2.0);
        variables4.put("y_2", 3.0);
        System.out.println("x_1 + y_2: " + evaluate("x_1 + y_2", variables4)); // 输出结果

//        String formula5 = "2+3*4/2-1a";
//        Map<String, Double> variables5 = new HashMap<>();
//        System.out.println(formula5 + evaluate(formula5, variables5)); // 输出结果

        String formula8 = "Math.pow(a,b)"; // 返回x的y次幂
        Map<String, Double> variables8 = new HashMap<>();
        variables8.put("a", 2.0);
        variables8.put("b", 3.0);        System.out.println(formula8+":"+ evaluate(formula8, variables8)); // 输出结果：8.0

        String formula9 = "Math.sqrt(a)";
        Map<String, Double> variables9 = new HashMap<>();
        variables9.put("a", 16D);
        System.out.println(formula9+":"+ evaluate(formula9, variables9)); // 输出结果：：8.0
    }


}
